using System.Text.RegularExpressions;

namespace AuthService.Domain.ValueObjects;

/// <summary>
/// 邮箱地址值对象
/// 确保邮箱地址的格式正确性和不可变性
/// </summary>
public sealed class Email : IEquatable<Email>
{
    private static readonly Regex EmailRegex = new(
        @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
        RegexOptions.Compiled | RegexOptions.IgnoreCase);

    /// <summary>
    /// 邮箱地址值
    /// </summary>
    public string Value { get; }

    /// <summary>
    /// 邮箱域名部分
    /// </summary>
    public string Domain => Value.Split('@')[1];

    /// <summary>
    /// 邮箱用户名部分
    /// </summary>
    public string LocalPart => Value.Split('@')[0];

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="value">邮箱地址</param>
    /// <exception cref="ArgumentException">邮箱格式无效时抛出</exception>
    public Email(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            throw new ArgumentException("邮箱地址不能为空", nameof(value));

        value = value.Trim().ToLowerInvariant();

        if (!IsValidEmail(value))
            throw new ArgumentException($"邮箱地址格式无效: {value}", nameof(value));

        Value = value;
    }

    /// <summary>
    /// 验证邮箱地址格式
    /// </summary>
    /// <param name="email">邮箱地址</param>
    /// <returns>是否有效</returns>
    public static bool IsValidEmail(string email)
    {
        if (string.IsNullOrWhiteSpace(email))
            return false;

        if (email.Length > 254) // RFC 5321 限制
            return false;

        return EmailRegex.IsMatch(email);
    }

    /// <summary>
    /// 创建邮箱对象（安全方式）
    /// </summary>
    /// <param name="value">邮箱地址</param>
    /// <returns>邮箱对象或null</returns>
    public static Email? TryCreate(string value)
    {
        try
        {
            return new Email(value);
        }
        catch
        {
            return null;
        }
    }

    /// <summary>
    /// 检查是否为企业邮箱
    /// </summary>
    /// <returns>是否为企业邮箱</returns>
    public bool IsBusinessEmail()
    {
        var commonPersonalDomains = new[]
        {
            "gmail.com", "yahoo.com", "hotmail.com", "outlook.com",
            "qq.com", "163.com", "126.com", "sina.com", "sohu.com"
        };

        return !commonPersonalDomains.Contains(Domain, StringComparer.OrdinalIgnoreCase);
    }

    /// <summary>
    /// 获取邮箱提供商
    /// </summary>
    /// <returns>邮箱提供商名称</returns>
    public string GetProvider()
    {
        return Domain.ToLowerInvariant() switch
        {
            "gmail.com" => "Google",
            "yahoo.com" => "Yahoo",
            "hotmail.com" or "outlook.com" => "Microsoft",
            "qq.com" => "腾讯",
            "163.com" or "126.com" => "网易",
            "sina.com" => "新浪",
            "sohu.com" => "搜狐",
            _ => "其他"
        };
    }

    /// <summary>
    /// 生成邮箱的哈希掩码（用于隐私保护）
    /// </summary>
    /// <returns>掩码后的邮箱</returns>
    public string ToMaskedString()
    {
        var parts = Value.Split('@');
        var localPart = parts[0];
        var domain = parts[1];

        if (localPart.Length <= 2)
            return $"{localPart[0]}***@{domain}";

        return $"{localPart[0]}***{localPart[^1]}@{domain}";
    }

    #region 相等性比较

    public bool Equals(Email? other)
    {
        if (other is null) return false;
        if (ReferenceEquals(this, other)) return true;
        return Value == other.Value;
    }

    public override bool Equals(object? obj)
    {
        return Equals(obj as Email);
    }

    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }

    public static bool operator ==(Email? left, Email? right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Email? left, Email? right)
    {
        return !Equals(left, right);
    }

    #endregion

    #region 类型转换

    public static implicit operator string(Email email)
    {
        return email.Value;
    }

    public static explicit operator Email(string value)
    {
        return new Email(value);
    }

    #endregion

    public override string ToString()
    {
        return Value;
    }
}
